package utils

import (
	"image"
	"image/gif"
	"image/jpeg"
	"image/png"
	"os"
	"path/filepath"
	"strings"
	"ubt-aio-service/app/pkg/logger"

	"github.com/nfnt/resize"
)

type images struct{}

var ImgProc = images{}

type imgInfo struct {
	CurImg    image.Image
	ImgWidth  int
	ImgHeight int
}

// ThumbImage 生成图片的缩略图
func (a *images) ThumbImage(srcPath, dstPath string, dw, dh int) {
	// 加载原图片文件，并获取其宽度及高度
	srcImg := a.LoadImage(srcPath)
	sw := srcImg.ImgWidth
	sh := srcImg.ImgHeight
	if dh == 0 {
		// 只限制宽度
		if sw <= dw {
			a.SaveImage(dstPath, srcImg.CurImg)
			return
		} else {
			dh = sh * dw / sw
		}
	} else {
		// 等比例缩放图片
		if sw <= dw && sh <= dh {
			a.SaveImage(dstPath, srcImg.CurImg)
			return
		} else if (sw / dw) > (sh / dh) {
			dh = sh * dw / sw
		} else {
			dw = sw * dh / sh
		}
	}
	dstImg := resize.Thumbnail(uint(dw), uint(dh), srcImg.CurImg, resize.Lanczos3)
	// 保存文件
	a.SaveImage(dstPath, dstImg)
}

// LoadImage 加载图片
func (a *images) LoadImage(path string) *imgInfo {
	// 打开文件
	file, err := os.Open(path)
	defer func(file *os.File) {
		err = file.Close()
		if err != nil {
			logger.Error("关闭文件失败。" + err.Error())
		}
	}(file)
	if err != nil {
		logger.Error("打开文件失败。" + err.Error())
		return nil
	}
	img, _, err := image.Decode(file)
	if err != nil {
		logger.Error("文件解码失败。" + err.Error())
		return nil
	}
	b := img.Bounds()
	width := b.Max.X
	height := b.Max.Y
	return &imgInfo{img, width, height}
}

// SaveImage 保存生成新的图片文件
func (a *images) SaveImage(path string, img image.Image) {
	file, err := os.OpenFile(path, os.O_SYNC|os.O_RDWR|os.O_CREATE, 0666)
	if err != nil {
		return
	}
	// 获取文件后缀名
	ext := filepath.Ext(path)
	if strings.EqualFold(ext, ".jpg") || strings.EqualFold(ext, ".jpeg") {
		if err = jpeg.Encode(file, img, &jpeg.Options{Quality: 100}); err != nil {
			return
		}
	} else if strings.EqualFold(ext, ".png") {
		if err = png.Encode(file, img); err != nil {
			return
		}
	} else if strings.EqualFold(ext, ".gif") {
		if err = gif.Encode(file, img, &gif.Options{NumColors: 256}); err != nil {
			return
		}
	}
}

// RemoveFile 删除服务器中的图片文件
func (a *images) RemoveFile(kind int64, path string) {
	var err error
	if kind == 1 {
		srcPath := strings.Replace(path, "/img/", "/img/src/", 1)
		thumbPath := strings.Replace(path, "/img/", "/img/thumb/", 1)
		if err = os.RemoveAll(srcPath); err != nil {
			return
		}
		if err = os.RemoveAll(thumbPath); err != nil {
			return
		}
	}
	if err = os.RemoveAll(path); err != nil {
		return
	}
}

// ImageCopy 裁剪图片
func (a *images) ImageCopy(srcImg image.Image, x, y, width, height int) image.Image {
	var (
		subImg   image.Image
		rgbaImg  *image.RGBA
		nrgbaImg *image.NRGBA
		ok       bool
	)
	if subImg, ok = srcImg.(*image.YCbCr); ok {
		subImg = rgbaImg.SubImage(image.Rect(x, y, x+width, y+height)).(*image.YCbCr)
	} else if rgbaImg, ok = srcImg.(*image.RGBA); ok {
		subImg = rgbaImg.SubImage(image.Rect(x, y, x+width, y+height)).(*image.RGBA)
	} else if nrgbaImg, ok = srcImg.(*image.NRGBA); ok {
		subImg = nrgbaImg.SubImage(image.Rect(x, y, x+width, y+height)).(*image.NRGBA)
	} else {
		return nil
	}
	return subImg
}

// ImgProc 图片处理入口方法
func (a *images) ImgProc(srcPath, dstPath string, x, y, width, height int) {
	// 加载图片
	srcImg := a.LoadImage(srcPath)
	// 创建新的图片对象
	dstImg := a.ImageCopy(srcImg.CurImg, x, y, width, height)
	// 保存生成新的图片文件
	a.SaveImage(dstPath, dstImg)
}
